#include "application.h"

#include "system/windowsmanager.h"


#include "graphics/graphicsmanager.h"
#include "graphics.opengl/renderer.h"

#include "inputs/manager.h"
#include "GameModeManager.h"

// GameModes
#include "flyby.h"
#include "gamenikoo.h"
#include "physicstests.h"

// Services
#include "serviceinputs.h"
#include "serviceworld.h"
#include "servicephysics.h"
#include "serviceentity.h"
#include "serviceaudio.h"
#include "servicegraphics.h"
#include "servicecamera.h"


#include "worldgridmanager.h"

namespace infinity {

Application::Application()
:	dw::system::Application()
,	m_window(NULL)
{
}

Application::~Application()
{
}

bool Application::onSetup(int argc, char** argv)
{
	dwLogInform("Setting up application\n");

	m_setup.commandLine.Parse(argc, argv);

	m_window = new dw::system::Window("Infinity", 800, 600, 32, false);

	m_window->registerListener(&m_windowEventListener);
	m_window->setTitle("Infinity 00.00.0000");
	m_window->show();

	dw::inputs::InputManager::createInstance().initialize(*m_window);

	initializeGraphics();
	initializeServices();

	//! @todo this should go in services
	//! @{
	WorldGridManager::getInstance().initialize();
	//! @}

	initializeGameModes();

	m_timer.reset();

	return true;
}

void Application::onIdle()
{
	dw::float32 deltaT = std::min((dw::float32)m_timer.getSeconds(), 0.033f);
	m_timer.reset();

	dw::system::WindowsManager::getInstance().handleEvents();

	if(m_window->isActive())
	{
		RECT rect;
		GetWindowRect(m_window->getHandle(),&rect);
		ShowCursor(false);
		SetCursorPos((rect.right-rect.left)/2,(rect.bottom-rect.top)/2);
	}
	


	//! @todo this should go in services
	//! @{
	dw::inputs::InputManager::getInstance().update();
	//! @}

	//! @todo clean
	dw::graphics::Renderer& renderer(dw::graphics::GraphicsManager::getInstance().getRenderer());

	renderer.setRenderState(dw::graphics::Renderer::RS_TEXTURE_2D, true);
	renderer.setRenderState(dw::graphics::Renderer::RS_CULLING, true);
	renderer.setRenderState(dw::graphics::Renderer::RS_CULL_MODE, dw::graphics::Renderer::CullMode::BACK);
	renderer.setRenderState(dw::graphics::Renderer::RS_SHADE_MODE, dw::graphics::Renderer::ShadeMode::FLAT);
	renderer.setRenderState(dw::graphics::Renderer::RS_FILL_MODE, dw::graphics::Renderer::FillMode::SOLID);
	renderer.setRenderState(dw::graphics::Renderer::RS_LIGHTING, false);
	renderer.setRenderState(dw::graphics::Renderer::RS_DEPTH_TEST, true);
	renderer.setRenderState(dw::graphics::Renderer::RS_DEPTH_FUNC, dw::graphics::Renderer::LESS);

	renderer.beginRender();

	try
	{
		ServiceManager::update(deltaT);
		GameModeManager::getInstance().update(deltaT);
	}
	catch (std::exception)
	{
		dwBreak();
	}

	GameModeManager::getInstance().render();

#ifdef INFINITY_DEBUG_TOOLS_ENABLED
	renderDebug();
#endif // INFINITY_DEBUG_TOOLS_ENABLED

	renderer.endRender();
}

void Application::onShutdown()
{
	dwLogInform("Shutting down application\n");

	ServiceManager::destroyAllServices();

	m_window->unregisterListener(&m_windowEventListener);

	delete m_window;
	m_window = NULL;
}

/*virtual*/ void Application::renderDebug()
{
	GameModeManager::getInstance().renderDebug();
	ServiceManager::renderDebug();
}

void Application::initializeServices()
{
	createService< ServiceInputs >();
	createService< ServicePhysics >();
	// createService< ServiceWorld >();
	createService< ServiceEntity >();
	createService< ServiceGraphics >();
	createService< ServiceAudio >();
	createService< ServiceCamera >();

	// registerDependency( ServiceWorld::Key, ServiceInputs::Key );

	registerDependency( ServiceEntity::Key, ServicePhysics::Key );
	registerDependency( ServiceEntity::Key, ServiceInputs::Key );

	registerDependency( ServicePhysics::Key, ServiceInputs::Key );
	// registerDependency( ServicePhysics::Key, ServiceWorld::Key );

	registerDependency( ServiceCamera::Key, ServiceInputs::Key );
	//registerDependency( ServiceCamera::Key, ServiceWorld::Key );

	registerDependency( ServiceGraphics::Key, ServiceCamera::Key );
	registerDependency( ServiceGraphics::Key, ServicePhysics::Key );

	registerDependency( ServiceAudio::Key, ServiceCamera::Key );
	registerDependency( ServiceAudio::Key, ServicePhysics::Key );
}

void Application::initializeGameModes()
{
	GameModeManager::getInstance().addGameMode(new FlyBy());
	// GameModeManager::getInstance().addGameMode(new GameNikoo());
	// GameModeManager::getInstance().addGameMode(new RenderTests());
	// GameModeManager::getInstance().addGameMode(new PhysicsTests());

	GameModeManager::getInstance().install();
}

void Application::initializeGraphics()
{
	dw::graphics::Backend::ContextSetup contextSetup(m_window);

	dw::graphics::GraphicsManager::getInstance().initialize(contextSetup);

	dw::graphics::Renderer* renderer = new dw::graphics::opengl::Renderer();
	dw::graphics::GraphicsManager::getInstance().setRenderer(renderer);
}

} // namespace infinity
